package com.coszero.utils.encryption

import android.text.TextUtils
import android.util.Base64
import android.util.Log
import com.coszero.utils.utils.StringUtils
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

/**
 * Desc： Base64编码工具类
 * 1.将图片编码base64,与解码
 *
 * @author ： xmqian
 * Email:xmqian93@163.com
 * Date: 2019/7/31 15:55
 * @version 3
 */
class Base64Utils private constructor() {
    init {
        throw UnsupportedOperationException("u con't instantiate me...")
    }

    companion object {
        private const val TAG: String = "Base64Utils"

        /**
         * 将图片转换成Base64编码的字符串
         *
         * @param path
         * @param flage CRLF：这个参数看起来比较眼熟，它就是Win风格的换行符，意思就是使用CR LF这一对作为一行的结尾而不是Unix风格的LF
         * DEFAULT：这个参数是默认，使用默认的方法来加密
         * NO_PADDING：这个参数是略去加密字符串最后的“=”
         * NO_WRAP：这个参数意思是略去所有的换行符（设置后CRLF就没用了）
         * URL_SAFE：这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符，具体就是以-和_取代+和
         * @return base64编码的字符串
         */
        /**
         * 去除换行符的base64字符串编码
         *
         * @param path
         * @return
         */
        @JvmOverloads
        fun imageToBase64(path: String, flage: Int = Base64.NO_WRAP): String? {
            if (TextUtils.isEmpty(path)) {
                return null
            }
            var `is`: InputStream? = null
            var data: ByteArray? = null
            var result: String? = null
            try {
                val file: File = File(path)
                `is` = FileInputStream(file)
                //创建一个字符流大小的数组。
                data = ByteArray(`is`.available())
                //写入数组
                `is`.read(data)
                //用默认的编码格式进行编码
                /*CRLF：这个参数看起来比较眼熟，它就是Win风格的换行符，意思就是使用CR LF这一对作为一行的结尾而不是Unix风格的LF
                DEFAULT：这个参数是默认，使用默认的方法来加密
                NO_PADDING：这个参数是略去加密字符串最后的“=”
                NO_WRAP：这个参数意思是略去所有的换行符（设置后CRLF就没用了）
                URL_SAFE：这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符，具体就是以-和_取代+和/ */
                result = Base64.encodeToString(data, flage)
            } catch (e: IOException) {
                e.printStackTrace()
            } finally {
                if (null != `is`) {
                    try {
                        `is`.close()
                    } catch (e: IOException) {
                        e.printStackTrace()
                    }
                }
            }
            return result
        }

        fun encodeToString(data: ByteArray?, flage: Int): String {
            return Base64.encodeToString(data, flage)
        }

        fun encodeToString(data: ByteArray?): String {
            return Base64.encodeToString(data, Base64.DEFAULT)
        }

        /**
         * base64编码字符集转化成图片文件。
         *
         * @param base64Str
         * @param path 文件存储路径
         * @return 是否成功
         */
        fun base64ToFile(base64Str: String?, path: String?): Boolean {
            val data: ByteArray = Base64.decode(base64Str, Base64.DEFAULT)
            for (i in data.indices) {
                if (data.get(i) < 0) {
                    //调整异常数据
                    data.get(i) = (data.get(i) + 256).toByte()
                }
            }
            var os: OutputStream? = null
            try {
                os = FileOutputStream(path)
                os.write(data)
                os.flush()
                os.close()
                return true
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
                return false
            } catch (e: IOException) {
                e.printStackTrace()
                return false
            }
        }

        /**
         * Reads a file and converts its content to a Base64 encoded string.
         *
         * @param audioFilePath The absolute path to the audio file.
         * @return The Base64 encoded string of the audio file content, or null if an error occurs.
         */
        fun audioToBase64(audioFilePath: String): String? {
            val audioFile: File = File(audioFilePath)
            if (!audioFile.exists() || !audioFile.isFile()) {
                Log.e(TAG, "Audio file not found or is not a valid file: " + audioFilePath)
                return null
            }

            var inputStream: InputStream? = null
            val buffer: ByteArray = ByteArray(audioFile.length().toInt())
            try {
                inputStream = FileInputStream(audioFile)
                val bytesRead: Int = inputStream.read(buffer)
                if (bytesRead != buffer.size) {
                    Log.e(TAG, "Failed to read the entire audio file.")
                    return null
                }
                return Base64.encodeToString(buffer, Base64.NO_WRAP) // NO_WRAP for cleaner output
            } catch (e: IOException) {
                Log.e(TAG, "Error reading audio file: " + e.message)
                return null
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close()
                    } catch (e: IOException) {
                        Log.e(TAG, "Error closing input stream: " + e.message)
                    }
                }
            }
        }

        /**
         * @param base64Str base64字符串解码成字节数组
         * @return
         */
        fun base64ToByteArray(base64Str: String?): ByteArray {
            return Base64.decode(base64Str, Base64.DEFAULT)
        }

        /**
         * 默认的base64字符串编码
         *
         * @return
         */
        fun encodeToStr(str: String): String {
            if (StringUtils.isEmpty(str)) {
                return ""
            }
            return Base64.encodeToString(str.toByteArray(), Base64.DEFAULT)
        }

        /**
         * 默认的base64字符串解码
         *
         * @return
         */
        fun decodeToStr(str: String): String {
            if (StringUtils.isEmpty(str)) {
                return ""
            }
            val decode: ByteArray = Base64.decode(str.toByteArray(), Base64.DEFAULT)
            return String(decode)
        }
    }
}
